/*
 * This file is part of PRO CFW.

 * PRO CFW is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * PRO CFW is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with PRO CFW. If not, see <http://www.gnu.org/licenses/ .
 */

/*
	PSP VSH 24bpp text bliter
*/
#include "common.h"
#include "font_chn.c"///+

//#define ALPHA_BLEND 1

extern unsigned char msx[];
static unsigned char *g_cur_font = msx;

static SceUID g_memid = -1;

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
int pwidth;
int pheight, bufferwidth, pixelformat;
unsigned int* vram32;

u32 fcolor = 0x00ffffff;
u32 bcolor = 0xff000000;

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
static u32 adjust_alpha(u32 col)
{
	u32 alpha = col>>24;
	u8 mul;
	u32 c1,c2;

	if(alpha==0)    return col;
	if(alpha==0xff) return col;

	c1 = col & 0x00ff00ff;
	c2 = col & 0x0000ff00;
	mul = (u8)(255-alpha);
	c1 = ((c1*mul)>>8)&0x00ff00ff;
	c2 = ((c2*mul)>>8)&0x0000ff00;
	return (alpha<<24)|c1|c2;
}

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//int blit_setup(int sx,int sy,const char *msg,int fg_col,int bg_col)
int blit_setup(void)
{
	int unk;
	sceDisplayGetMode(&unk, &pwidth, &pheight);
	sceDisplayGetFrameBuf((void*)&vram32, &bufferwidth, &pixelformat, PSP_DISPLAY_SETBUF_NEXTFRAME);
	if( (bufferwidth==0) || (pixelformat!=3)) return -1;

	fcolor = 0x00ffffff;
	bcolor = 0xff000000;

	return 0;
}

/////////////////////////////////////////////////////////////////////////////
// blit text
/////////////////////////////////////////////////////////////////////////////
void blit_set_color(int fg_col,int bg_col)
{
	fcolor = fg_col;
	bcolor = bg_col;
}

/////////////////////////////////////////////////////////////////////////////
// blit text
/////////////////////////////////////////////////////////////////////////////
int blit_string(int sx,int sy,const char *msg)
{
	int x,y,p;
	int offset;
	u8 code, font;
	u32 fg_col,bg_col;

	u32 col,c1,c2;
	u32 alpha;

	fg_col = adjust_alpha(fcolor);
	bg_col = adjust_alpha(bcolor);


//Kprintf("MODE %d WIDTH %d\n",pixelformat,bufferwidth);
	if( (bufferwidth==0) || (pixelformat!=3)) return -1;

	for(x=0;msg[x] && x<(pwidth/8);x++)
	{
		code = (u8)msg[x]; // no truncate now

		for(y=0;y<8;y++)
		{
			offset = (sy+y)*bufferwidth + sx+x*8;
			font = y>=7 ? 0x00 : g_cur_font[ code*8 + y ];
			for(p=0;p<8;p++)
			{
				col = (font & 0x80) ? fg_col : bg_col;
				alpha = col>>24;
				if(alpha==0) vram32[offset] = col;
				else if(alpha!=0xff)
				{
					c2 = vram32[offset];
					c1 = c2 & 0x00ff00ff;
					c2 = c2 & 0x0000ff00;
					c1 = ((c1*alpha)>>8)&0x00ff00ff;
					c2 = ((c2*alpha)>>8)&0x0000ff00;
					vram32[offset] = (col&0xffffff) + c1 + c2;
				}

				font <<= 1;
				offset++;
			}
		}
	}
	return x;
}

int blit_string_chs(int sx,int sy,const char *msg)///+
{
	int x,y,p;
	int offset,font_offset;
	unsigned char code1,code2;
	u8 *font;
	u32 fg_col,bg_col;

	u32 col,c1,c2;
	u32 alpha;

	fg_col = adjust_alpha(fcolor);
	bg_col = adjust_alpha(bcolor);

	if( (bufferwidth==0) || (pixelformat!=3)) 
	{
		return -1;
	}

	x = 0;
	while (msg[x] && x<(pwidth/8))
	{
		code1 = msg[x];
		if (code1 < 128)
		{
			code2 = 0;
			font = &msx2[ code1 * 12 ];
			for(y=0;y<12;y++,font++)
			{
				for(p=0;p<6;p++)
				{
					col = (*font & (128 >> p)) ? fg_col : bg_col;
					alpha = col>>24;
					offset = (sy+y)*bufferwidth + sx+x*6+p;
					if(alpha==0) vram32[offset] = col;
					else if(alpha!=0xff)
					{
						c2 = vram32[offset];
						c1 = c2 & 0x00ff00ff;
						c2 = c2 & 0x0000ff00;
						c1 = ((c1*alpha)>>8)&0x00ff00ff;
						c2 = ((c2*alpha)>>8)&0x0000ff00;
						vram32[offset] = (col&0xffffff) + c1 + c2;
					}
				}
			}
			x++;
		}
		else
		{
			code2 = msg[x+1];

			if( (code1 >= 0xA1) && (code1 <= 0xFE) && (code2 >= 0xA1) && (code2 <= 0xFE) )
				font_offset = 24 + ((94*(code1-0xA1)+(code2-0xA1))*24);
			else
				font_offset = 0;

			if(font_offset+24 > sizeof(msx3))
				font_offset = 0;

			font = &msx3[ font_offset ];
			for(y=0;y<12;y++,font+=2)
			{
				for(p=0;p<12;p++)
				{
					if (p < 8)
						col = (*font & (128 >> p)) ? fg_col : bg_col;
					else
						col = (*(font+1) & (128 >> (p-8))) ? fg_col : bg_col;
					alpha = col>>24;
					offset = (sy+y)*bufferwidth + sx+x*6+p;
					if(alpha==0) vram32[offset] = col;
					else if(alpha!=0xff)
					{
						c2 = vram32[offset];
						c1 = c2 & 0x00ff00ff;
						c2 = c2 & 0x0000ff00;
						c1 = ((c1*alpha)>>8)&0x00ff00ff;
						c2 = ((c2*alpha)>>8)&0x0000ff00;
						vram32[offset] = (col&0xffffff) + c1 + c2;
					}
				}
			}
			x+=2;
		}
	}
	return x;
}

int blit_string_cht(int sx,int sy,const char *msg)///+
{
	int x,y,p;
	int offset,font_offset;
	unsigned char code1,code2;
	u8 *font;
	u32 fg_col,bg_col;

	u32 col,c1,c2;
	u32 alpha;

	fg_col = adjust_alpha(fcolor);
	bg_col = adjust_alpha(bcolor);

	if( (bufferwidth==0) || (pixelformat!=3)) 
	{
		return -1;
	}

	x = 0;
	while (msg[x] && x<(pwidth/8))
	{
		code1 = msg[x];
		if (code1 < 128)
		{
			code2 = 0;
			font = &msx2[ code1 * 12 ];
			for(y=0;y<12;y++,font++)
			{
				for(p=0;p<6;p++)
				{
					col = (*font & (128 >> p)) ? fg_col : bg_col;
					alpha = col>>24;
					offset = (sy+y)*bufferwidth + sx+x*6+p;
					if(alpha==0) vram32[offset] = col;
					else if(alpha!=0xff)
					{
						c2 = vram32[offset];
						c1 = c2 & 0x00ff00ff;
						c2 = c2 & 0x0000ff00;
						c1 = ((c1*alpha)>>8)&0x00ff00ff;
						c2 = ((c2*alpha)>>8)&0x0000ff00;
						vram32[offset] = (col&0xffffff) + c1 + c2;
					}
				}
			}
			x++;
		}
		else
		{
			code2 = msg[x+1];

			if( (code1 >= 0XA1) && (code1 <= 0XF9) && (code2 >= 0x40) && (code2 <= 0x7E) )
				font_offset = 24 + ((157*(code1-0XA1)+(code2-0x40))*24);
			else if( (code1 >= 0XA1) && (code1 <= 0XF9) && (code2 >= 0xA1) && (code2 <= 0xFE) )
				font_offset = 24 + ((157*(code1-0XA1)+(code2-0xA1+63))*24);
			else
				font_offset = 0;

			if(font_offset+24 > sizeof(msx4))
				font_offset = 0;

			font = &msx4[ font_offset ];
			for(y=0;y<12;y++,font+=2)
			{
				for(p=0;p<12;p++)
				{
					if (p < 8)
						col = (*font & (128 >> p)) ? fg_col : bg_col;
					else
						col = (*(font+1) & (128 >> (p-8))) ? fg_col : bg_col;
					alpha = col>>24;
					offset = (sy+y)*bufferwidth + sx+x*6+p;
					if(alpha==0) vram32[offset] = col;
					else if(alpha!=0xff)
					{
						c2 = vram32[offset];
						c1 = c2 & 0x00ff00ff;
						c2 = c2 & 0x0000ff00;
						c1 = ((c1*alpha)>>8)&0x00ff00ff;
						c2 = ((c2*alpha)>>8)&0x0000ff00;
						vram32[offset] = (col&0xffffff) + c1 + c2;
					}
				}
			}
			x+=2;
		}
	}
	return x;
}

int blit_string_ctr(int sy,const char *msg)
{
	int sx = 480/2;

#ifdef CONFIG_639
	if(psp_fw_version == FW_639)
		sx = 480/2-scePaf_strlen(msg)*(8/2);
#endif

#ifdef CONFIG_635
	if(psp_fw_version == FW_635)
		sx = 480/2-scePaf_strlen(msg)*(8/2);
#endif

#ifdef CONFIG_620
	if(psp_fw_version == FW_620)
		sx = 480/2-scePaf_strlen_620(msg)*(8/2);
#endif

#ifdef CONFIG_660
	if(psp_fw_version == FW_660)
		sx = 480/2-scePaf_strlen_660(msg)*(8/2);
#endif

	return blit_string(sx,sy,msg);
}

int load_external_font(const char *file)

{
	SceUID fd;
	size_t f_si;
	int ret;
	void *buf;

	fd = sceIoOpen(file, PSP_O_RDONLY, 0777);

	if(fd < 0) {
		return fd;
	}

	sceIoLseek(fd, 0, PSP_SEEK_END);
	f_si = sceIoLseek(fd, 0, PSP_SEEK_CUR);
	sceIoLseek(fd, 0, PSP_SEEK_SET);

	g_memid = sceKernelAllocPartitionMemory(2, "proDebugScreenFontBuffer", PSP_SMEM_High, f_si, NULL);

	if(g_memid < 0) {
		sceIoClose(fd);
		return g_memid;
	}

	buf = sceKernelGetBlockHeadAddr(g_memid);

	if(buf == NULL) {
		sceKernelFreePartitionMemory(g_memid);
		sceIoClose(fd);
		return -2;
	}

	ret = sceIoRead(fd, buf, f_si);

	if(ret != f_si) {
		sceKernelFreePartitionMemory(g_memid);
		sceIoClose(fd);
		return -3;
	}

	sceIoClose(fd);
	g_cur_font = buf;

	return 0;
}

void release_font(void)
{
	if(g_memid >= 0) {
		sceKernelFreePartitionMemory(g_memid);
		g_memid = -1;
	}

	g_cur_font = msx;
}
